package pl.edu.agh.abd.hsmest;

import java.lang.reflect.Method;

import pl.cyfronet.gforge.hsmest.hsmmon.HSMMonResource;
import pl.cyfronet.gforge.hsmest.hsmmon.HSMMonResourceHome;
import pl.cyfronet.gforge.hsmest.hsmmon.stubs.Slot;
import pl.cyfronet.gforge.hsmest.hsmmon.stubs.StorageSystemInfo;
import pl.cyfronet.gforge.hsmest.hsmmon.stubs.HSMFileInfo;
import pl.cyfronet.gforge.hsmest.hsmmon.stubs.HSMState;
import pl.cyfronet.gforge.hsmest.hsmmon.stubs.HSMLibrary;
import pl.cyfronet.gforge.hsmest.hsmmon.stubs.Drive;
import pl.cyfronet.gforge.hsmest.hsmmon.stubs.Tape;
import pl.cyfronet.gforge.hsmest.hsmmon.stubs.HSMDriveState;

import javax.xml.parsers.*;
import javax.xml.xpath.*;

import org.w3c.dom.*;

public class HSMInitializer {

	HSMMonResource hsmMonResource;
	XPath xpath;
	Document systemDocument;
	Document queueDocument;

	private static int TAPES = 10;

	public static void main(String[] args) throws Exception {
		HSMInitializer hsdf = new HSMInitializer();
		// hsdf.getStorageSystemInfo();
		hsdf.initialize();
		

	}

	public HSMInitializer() {
		DocumentBuilderFactory domFactory = DocumentBuilderFactory
				.newInstance();
		domFactory.setNamespaceAware(true); // never forget this!
		DocumentBuilder builder;
		try {
			builder = domFactory.newDocumentBuilder();
			systemDocument = builder.parse("config/system.xml");
			queueDocument = builder.parse("config/queue.xml");
			XPathFactory factory = XPathFactory.newInstance();
			xpath = factory.newXPath();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	public HSMMonResource initialize() {
		hsmMonResource = new HSMMonResource();
		try {
			hsmMonResource.setSystemInfo(this.generateStorageSystemInfo());
			hsmMonResource.setTapeMap(this.generateTapes());
			hsmMonResource.setLibraries(this.generateHSMLibraries());
			HSMState state = new HSMState();
			state.setDrive(this.generateDriveStates());
			state.setFileQueue(this.generateFileInfos());
			hsmMonResource.setSystemState(state);
		} catch (XPathExpressionException e) {
			hsmMonResource = null;
			e.printStackTrace();
		}

		return hsmMonResource;
	}

	protected StorageSystemInfo generateStorageSystemInfo()
			throws XPathExpressionException {
		StorageSystemInfo storageSystemInfo = new StorageSystemInfo();

		NodeList nl = (NodeList) xpath.evaluate("/storage-system/*",
				systemDocument, XPathConstants.NODESET);
		fillClass(storageSystemInfo, nl);
		return storageSystemInfo;
	}

	protected HSMLibrary[] generateHSMLibraries()
			throws XPathExpressionException {

		NodeList nl = (NodeList) xpath.evaluate("/storage-system/library",
				systemDocument, XPathConstants.NODESET);
		HSMLibrary[] hsmLibraries = new HSMLibrary[nl.getLength()];
		for (int i = 0; i < nl.getLength(); i++) {
			HSMLibrary lib = new HSMLibrary();
			fillClass(lib, nl.item(i).getChildNodes());
			lib.setId(Integer.parseInt(((Element) nl.item(i))
					.getAttribute("id")));
			Drive[] drives = this.generateDrives(nl.item(i).getChildNodes());
			lib.setDrive(drives);
			lib.setNumberOfDrives(drives.length);
			int slots = TAPES / nl.getLength()
					+ ((i < TAPES % nl.getLength()) ? 1 : 0);
			lib.setNumberOfSlots(slots);
			lib.setInventory(this.generateSlots(slots, nl.getLength(), i));
			hsmLibraries[i] = lib;

		}
		return hsmLibraries;
	}

	protected Drive[] generateDrives(NodeList parentLib)
			throws XPathExpressionException {
		NodeList nl = (NodeList) xpath.evaluate("drive", parentLib,
				XPathConstants.NODESET);
		Drive[] drives = new Drive[nl.getLength()];

		for (int i = 0; i < nl.getLength(); i++) {
			Drive drive = new Drive();
			fillClass(drive, nl.item(i).getChildNodes());
			drive.setId(Integer.parseInt(((Element) nl.item(i))
					.getAttribute("id")));
			drives[i] = drive;
			
		}
		return drives;

	}

	protected Tape[] generateTapes() {
		Tape[] tapes = new Tape[TAPES];
		int sizes[] = { 512, 1024, 2048 };
		for (int i = 0; i < TAPES; i++) {
			Tape tape = new Tape();
			tape.setTapeID("Tape-" + (i + 1));
			tape.setCapacity(1024 * 1024 * 1024 * ((i % 2 == 1) ? 4 : 2)); // 2
																			// lub
																			// 4
																			// GB
			tape.setBlockSize(sizes[i % 3]);
			tapes[i] = tape;
		}

		return tapes;

	}

	protected Slot[] generateSlots(int numberOfSlots, int numberOfLibs, int partNumber) {
		Slot[] slots = new Slot[numberOfSlots];
		for(int j = 0; j<numberOfSlots; j++){
			slots[j] = new Slot(j+1, "Tape-" + (partNumber + 1 + j*numberOfLibs));
		}
		return slots;
	}

	protected HSMDriveState[] generateDriveStates()
			throws XPathExpressionException {
		NodeList nl = (NodeList) xpath.evaluate("/queueState/driveState",
				queueDocument, XPathConstants.NODESET);
		HSMDriveState[] states = new HSMDriveState[nl.getLength()];
		for (int i = 0; i < nl.getLength(); i++) {
			HSMDriveState driveState = new HSMDriveState();
			fillClass(driveState, nl.item(i).getChildNodes());
			driveState.setId(Integer.parseInt(((Element) nl.item(i))
					.getAttribute("id")));

			states[i] = driveState;
		}
		return states;
	}

	protected HSMFileInfo[] generateFileInfos() throws XPathExpressionException {
		NodeList nl = (NodeList) xpath.evaluate("/queueState/fileInfo",
				queueDocument, XPathConstants.NODESET);
		HSMFileInfo[] states = new HSMFileInfo[nl.getLength()];
		for (int i = 0; i < nl.getLength(); i++) {
			HSMFileInfo fileInfo = new HSMFileInfo();
			fillClass(fileInfo, nl.item(i).getChildNodes());
			states[i] = fileInfo;
		}
		return states;
	}

	@SuppressWarnings("unchecked")
	private void fillClass(Object o, NodeList nl) {
		@SuppressWarnings("rawtypes")
		Class currentClass = o.getClass();
		for (int j = 0; j < nl.getLength(); j++) {
			if (nl.item(j).getChildNodes().getLength() == 1) {
				Method m;
				try {
					m = currentClass.getMethod("set"
							+ capitalize(nl.item(j).getNodeName()),
							String.class);
					m.invoke(o, nl.item(j).getTextContent());
					continue;
				} catch (Exception e) {
				}

				try {
					m = currentClass.getMethod("set"
							+ capitalize(nl.item(j).getNodeName()), int.class);
					m.invoke(o, Integer.parseInt(nl.item(j).getTextContent()));
					continue;
				} catch (Exception e1) {
				}
				try {
					m = currentClass
							.getMethod("set"
									+ capitalize(nl.item(j).getNodeName()),
									float.class);
					m.invoke(o, Float.parseFloat(nl.item(j).getTextContent()));
					continue;
				} catch (Exception e2) {
				}
				try {
					m = currentClass.getMethod("set"
							+ capitalize(nl.item(j).getNodeName()),
							boolean.class);
					m.invoke(o,
							Boolean.parseBoolean(nl.item(j).getTextContent()));
					continue;
				} catch (Exception e2) {
				}
			}
		}
	}

	public static void pr(String str) {
		System.out.println(str);
	}

	public static void dump(Object o) {
		Method[] fields = o.getClass().getDeclaredMethods();
		System.out.println(o.getClass().getName());
		for (int i = 0; i < fields.length; i++) {
			if (fields[i].getName().startsWith("get")
					&& fields[i].getParameterTypes().length == 0) {
				try {
					System.out.println("   " + fields[i].getName() + " - "
							+ fields[i].invoke(o));
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}

	public static String capitalize(String s) {
		return s.substring(0, 1).toUpperCase() + s.substring(1);
	}
}
